package mango.orm.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import mango.functions.FuncString;
import mango.orm.Dao;
import mango.orm.OrmException;
import mango.orm.SQLMaker;
import mango.orm.entity.Entity;
import mango.orm.entity.EntityException;


public abstract class AbstractSQLMaker implements SQLMaker {
    private static Map<String, String> QUERY_SQL = new HashMap<String, String>();
    private static Map<String, String> INSERT_SQL = new HashMap<String, String>();
    private static Map<String, String> DELETE_SQL = new HashMap<String, String>();
    private static Map<String, String> UPDATE_SQL = new HashMap<String, String>();
    
    public abstract String getLimitSql(String sql, int start, int limit);

    public String getCountSql(String sql) {
        StringBuilder ret = new StringBuilder();
        ret.append("select count(1) count from (").append(sql).append(") ").append("cnttmp").append(System.currentTimeMillis());
        return ret.toString();
    }

    public String getQuerySql(Entity entity) {
        if (FuncString.isBlank(entity.getTableName()) || entity.getPrimarys().size() == 0||entity.getClass() == Entity.class) {
            throw new EntityException("illegal entity!");
        }
        String result = QUERY_SQL.get(entity.getClass().getName());
        if(result == null) {
            StringBuilder selectSql = new StringBuilder();
            StringBuilder primaryCondition = new StringBuilder();
            selectSql.append("select ");
            for (String column : entity.getFieldNames()) {
                selectSql.append(column);
                selectSql.append(", ");
                if (entity.isPrimary(column)) {
                    primaryCondition.append(" and ").append(column).append("=?");
                }
            }
            selectSql.delete(selectSql.length() - 2, selectSql.length());
            long time = System.currentTimeMillis();
            selectSql.append(" from ").append(entity.getTableName());
            selectSql.append(" where '").append(time).append("'='").append(time).append("'");
            selectSql.append(primaryCondition);
            result = selectSql.toString();
            QUERY_SQL.put(entity.getClass().getName(), result);   
        }
        return result;
    }

    public String getInsertSql(Entity entity) {
        if(FuncString.isBlank(entity.getTableName()) || entity.getClass() == Entity.class) {
            throw new EntityException("illegal entity!");
        }
        String ret = null;
        if (ret == null) {
            StringBuilder sql = new StringBuilder();
            sql.append("insert into ").append(entity.getTableName()).append("(");
            StringBuilder values = new StringBuilder().append(" values(");
            for (String column : entity.getFieldNames()) {
                sql.append(column);
                sql.append(", ");
                values.append("?, ");
            }
            sql.delete(sql.length() - 2, sql.length());
            values.delete(values.length() - 2, values.length());
            sql.append(")").append(values).append(")");
            ret = sql.toString();
            INSERT_SQL.put(entity.getClass().getName(), ret);
        }
        return ret;
    }

    public String getUpdateSql(Entity entity) {
        if (FuncString.isBlank(entity.getTableName()) || entity.getPrimarys().size() == 0||entity.getClass() == Entity.class) {
            throw new EntityException("illegal entity!");
        }
        String ret = UPDATE_SQL.get(entity.getClass().getName());
        if (ret == null) {
            StringBuilder sql = new StringBuilder();
            StringBuilder condition = new StringBuilder();
            sql.append("update ").append(entity.getTableName()).append(" set ");
            for (String column : entity.getFieldNames()) {
                if (entity.isPrimary(column)) {
                    condition.append(" and ").append(column).append("=?");
                }
                else {
                    sql.append(column).append("=?");
                    sql.append(", ");
                }
            }
            sql.delete(sql.length() - 2, sql.length());
            long time = System.currentTimeMillis();
            sql.append(" where '").append(time).append("'='").append(time).append("'").append(condition);
            ret = sql.toString();
            UPDATE_SQL.put(entity.getClass().getName(), ret);
        }
        return ret;
    }

    public String getDeleteSql(Entity entity) {
        if (FuncString.isBlank(entity.getTableName()) || entity.getPrimarys().size() == 0||entity.getClass() == Entity.class) {
            throw new EntityException("illegal entity!");
        }
        String ret = DELETE_SQL.get(entity.getClass().getName());
        if (ret == null) {
            StringBuilder sql = new StringBuilder();
            sql.append("delete from ").append(entity.getTableName());
            long time = System.currentTimeMillis();
            sql.append(" where '").append(time).append("'='").append(time).append("'");
            for (String primary : entity.getPrimarys()) {
                sql.append(" and ").append(primary).append("=?");
            }
            ret = sql.toString();
            DELETE_SQL.put(entity.getClass().getName(), ret);
        }
        return ret;
    }

    public int getDaoTypeBySql(String sql) {
        if (sql == null) {
            throw new NullPointerException();
        }
        String temp = sql.toUpperCase().trim();
        if (temp.startsWith("SELECT")) {
            return Dao.TYPE_QUERY;
        }
        else if (temp.startsWith("INSERT")) {
            return Dao.TYPE_CREATE;
        }
        else if (temp.startsWith("UPDATE")) {
            return Dao.TYPE_UPDATE;
        }
        else if (temp.startsWith("DELETE")) {
            return Dao.TYPE_DELETE;
        }
        else {
            return Dao.TYPE_OTHER;
        }
    }
    
    public String formatSubSql(String sql, List<String> subSql) {
        try {
            if (subSql == null || subSql.size() == 0) {
                return sql;
            }
            for (int i = 0; i < subSql.size(); i++) {
                sql = sql.replaceAll("\\{" + i + "}", subSql.get(i));
            }
            sql = sql.replaceAll("\\{\\d}", "");
            return sql;
        }
        catch(Exception e) {
            throw new OrmException("SubSql error : " + subSql, e);
        }
    }
}
